<template>
  <canvas ref="canvas" style="width: 500px"></canvas>
  <div>
    <button>Loading</button>
    <button @click="run">Run</button>
  </div>
</template>

<script>
import * as PIXI from 'pixi.js'
import * as TWEEN from '@tweenjs/tween.js'

const width = 1000
const height = 1000
const stageTween = []

let app = null
let container = null
const arcList = [
  {
    width: .3,
    height: .07,
    color: [
      {
        offset: 0,
        color: 'rgba(255, 199, 36, .42)'
      },
      {
        offset: .8,
        color: 'rgba(255, 199, 36, .42)'
      },
      {
        offset: 1,
        color: 'rgba(253, 160, 1, 1)'
      }
    ],
    light: {
      position: {
        x: 0,
        y: 300
      },
      color: 0xfda001,
      opacity: .5
    }
  },
  {
    width: .4,
    height: .085,
    color: [
      {
        offset: 0,
        color: 'rgba(255, 199, 36, .2)'
      },
      {
        offset: .8,
        color: 'rgba(255, 199, 36, .2)'
      },
      {
        offset: 1,
        color: 'rgba(253, 160, 1, .7)'
      }
    ],
    // light: {
    //   position: {
    //     x: 0,
    //     y: 200
    //   }
    // }
  },
  {
    width: .6,
    height: .1,
    color: [
      {
        offset: 0,
        color: 'rgba(255, 199, 36, .2)'
      },
      {
        offset: .8,
        color: 'rgba(255, 199, 36, .2)'
      },
      {
        offset: 1,
        color: 'rgba(253, 160, 1, .5)'
      }
    ],
    light: {
      position: {
        x: 0,
        y: 450
      },
      color: 0xfda001,
      opacity: .3
    }
  },
  {
    width: .8,
    height: .16,
    color: [
      {
        offset: 0,
        color: 'rgba(255, 199, 36, .1)'
      },
      {
        offset: .8,
        color: 'rgba(255, 199, 36, .1)'
      },
      {
        offset: 1,
        color: 'rgba(253, 160, 1, .2)'
      }
    ]
  }
]
const planets = [
  {
    radius: 10,
    width: 350,
    height: 40,
    color: 0xFFC724,
    lineStyle: 0xFDA001,
    lineWidth: 2,
    lineOpacity: .5,
    offset: {
      x: 10,
      y: -40
    },
    speed: 1
  },
  {
    radius: 15,
    width: 380,
    height: 70,
    color: 0xFFC724,
    lineStyle: 0xFDA001,
    lineWidth: 2,
    lineOpacity: .5,
    speed: .8
  },
  {
    radius: 20,
    width: 420,
    height: 80,
    color: 0xFFC724,
    lineStyle: 0xFFC724,
    lineWidth: 2,
    offset: {
      y: -20
    },
    speed: -.5
  }
]

function createArcRadialGradient(colors) {
  const w = 200
  const h = 200
  const c = document.createElement('canvas')
  c.width = w 
  c.height = h
  const ctx = c.getContext('2d')
  const grd = ctx.createRadialGradient(100, 100, 0, 100, 100, 100)
  
  ;[].concat(colors).forEach(({offset, color}) => {
    grd.addColorStop(offset, color)
  })

  ctx.fillStyle = grd
  ctx.arc(100, 100, 100, 0, Math.PI * 2)
  ctx.fill()

  return PIXI.Texture.from(c)
}

function createLinearGradient() {
  const quality = 200
  const c = document.createElement('canvas')
  c.width = 100
  c.height = quality
  const ctx = c.getContext('2d')
  const grd = ctx.createLinearGradient(0, 0, 0, quality)
  grd.addColorStop(.1, 'rgba(0, 0, 0, 1)')
  grd.addColorStop(.8, 'rgba(255, 255, 255, .5)')
  grd.addColorStop(1, 'rgba(0, 0, 0, 1)')

  ctx.fillStyle = grd
  ctx.fillRect(0, 0, 100, quality)

  return PIXI.Texture.from(c)
}

export default {
  data() {
    return {
      time: 1000
    }
  },
  mounted() {
    this.draw()
  },
  methods: {
    draw() {
      app = new PIXI.Application({
        view: this.$refs.canvas,
        width,
        height,
        antialias: true,
        resolution: window.devicePixelRatio,
        backgroundColor: 0x000000
      })

      this.arcContainer()
      this.drawPlanetaryContainer(planets)
      app.ticker.add(() => {
        TWEEN.update(app.ticker.lastTime)
      })
    },
    arcContainer() {
      container = new PIXI.Container()
      container.position.set(width/2, height* 3/4)
      app.stage.addChild(container)

      arcList.forEach(({width: w, height: h, color, light}) => {
        w = width * w
        h = height * h
        let arc = this.drawArc(0, 0, color)
        
        const coords = { w: 0, h: 0 }
        const tween = new TWEEN.Tween(coords)
          .to({ w, h }, this.time)
          .easing(TWEEN.Easing.Quadratic.Out)
          .onUpdate(() => {
            arc.width = coords.w
            arc.height = coords.h
          })

        if (light) {
          light = {...light, w}
          let lightArc = this.drawLight(light)
          container.addChild(lightArc)
        }

        stageTween.push(tween)
        container.addChild(arc)
      })
    },
    drawArc(w, h, color) {
      const arc = new PIXI.Sprite(createArcRadialGradient(color))
      arc.position.set(0, 0)
      arc.anchor.set(0.5)
      arc.width = w
      arc.height = h

      return arc
    },
    drawLight(light) {
      const graphics = new PIXI.Graphics()
      const spr = new PIXI.Sprite(createLinearGradient())

      // 追加到舞台
      app.stage.addChild(spr)
      spr.anchor.set(.5, 1)
      spr.width = width
      graphics.mask = spr

      let { w, color, opacity } = light

      const drawPath = (w) => {
        let { x, y } = light.position
        let lx = w / 2
        let path = [lx, 0]
        // 底座容器相对画布的位置
        let container_x = width / 2
        let container_y = height * 3/4
        let __h = container_y + y
        let tan = Math.tan(container_x / __h)
        let currentTan = Math.tan(lx/y)
        let maskH = 0
  
        // 如果 正切大于当前位置形成的三角正切 则x已知
        if (currentTan > tan) {
          let _y = container_x / lx * y - y
          maskH = Math.abs(_y)
          path.push(container_x, -_y, -container_x, -_y,)
        } else {
          let _x = currentTan * __h
          maskH = Math.abs(container_y)
          path.push(_x, -container_y, -_x, -container_y)
        }
  
        path.push(-lx, 0)
        graphics.lineStyle(0)
        graphics.beginFill(color, opacity)
        graphics.drawPolygon(path)
        graphics.endFill()
      
        spr.position.set(container_x, container_y)
        spr.height = maskH
      }

      const coords = {w: 0}
      const tween = new TWEEN.Tween(coords)
        .to({ w }, this.time)
        .onUpdate(() => {
          console.log(coords)
          graphics.clear()
          drawPath(coords.w)
        })
      stageTween.push(tween)

      return graphics
    },
    drawPlanetaryContainer() {
      const container = new PIXI.Container()
      container.position.set(width/2, height* 3/4)
      app.stage.addChild(container)

      ;[].concat(planets).forEach(item => {
        this.drawPlanetary(item, container)
      })
    },
    drawPlanetary(item, container) {
      let { 
        radius = 10, 
        width = 0, 
        height = 0,
        speed,
        lineStyle = 0xffffff,
        lineWidth = 1,
        lineOpacity = 1 
      } = item
      const graphics = new PIXI.Graphics()
        .lineStyle(lineWidth, lineStyle, lineOpacity)
        .drawEllipse(0, 0, width, height)
        .endFill()

      if (item.offset) {
        let {x = 0, y = 0} = item.offset
        graphics.position.set(x, y)
      }
      item.offset = {x: 0, y: 0, ...item.offset}

      const planet = new PIXI.Graphics()
        .lineStyle(0)
        .beginFill(item.color)
        .drawCircle(0, 0, radius)
        .endFill()
      planet.filters = [new PIXI.filters.BlurFilter(3)]

      let angle = 0
      const spin = (el, w, h, speed = 1) => {
        if (!w && !h) return
        let {x: _x, y: _y} = item.offset

        angle *= angle !== 360
        angle += speed

        let t = Math.tan(angle / 360 * Math.PI)
        let x = w * (1 - t ** 2) / (1 + t ** 2) + _x
        let y = h * 2 * t / (1 + t ** 2) + _y

        el.position.set(x, y)
      }

      // app.ticker.add(delta => {
      //   spin(planet, width, height, speed)
      // })

      container.addChild(graphics)
      container.addChild(planet)
    },
    run() {
      stageTween.forEach(tween => {
        tween.start()
      })
    }
  }
}
</script>

<style>

</style>